package com.xinmao.quantitative.service.data;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xinmao.quantitative.api.EastMoneyDataApi;
import com.xinmao.quantitative.api.EastMoneyETFMarketDataApi;
import com.xinmao.quantitative.api.EastMoneyStockMarketDataApi;
import com.xinmao.quantitative.api.model.*;
import com.xinmao.quantitative.constant.Constants;
import com.xinmao.quantitative.entity.*;
import com.xinmao.quantitative.enums.EastMoneyPeriodEnum;
import com.xinmao.quantitative.enums.MarketEnum;
import com.xinmao.quantitative.repository.*;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Title: LoadDataService
 * @Author: XYe13
 * @Date: 4/30/2024 13:44
 * @Description:
 */
@Service
@Slf4j
public class LoadDataServiceImpl implements ILoadDataService {

    @Resource
    private EastMoneyDataApi eastMoneyDataApi;
    @Resource
    private EastMoneyETFMarketDataApi eastMoneyETFMarketDataApi;
    @Resource
    private EastMoneyStockMarketDataApi eastMoneyStockMarketDataApi;
    @Resource
    private StockDayRepository stockDayRepository;
    @Resource
    private Stock30Repository stock30Repository;
    @Resource
    private Stock5Repository stock5Repository;
    @Resource
    private Stock15Repository stock15Repository;
    @Resource
    private FundRepository fundRepository;


    /**
     * 获取按周期获取数据
     * @param symbol 代码
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param period 周期
     * @param adjust 调整
     * */
    @Override
    public List<StockDayEntity> loadStockKline(String symbol, String startDate, String endDate, String period, String adjust) {
        EastMoneyZhAHisDayRequest request = new EastMoneyZhAHisDayRequest();
        request.setEnd(endDate);
        request.setBeg(startDate);
        request.setSecid(getStockSymbolCode(symbol));
        List<StockDayEntity> entities = getKEntities(period, adjust, request);
//        saveStockDay(entities,period);
        return entities;
    }

    @Override
    public List<StockDayEntity> loadFundKline(String symbol, String startDate, String endDate, String period, String adjust) {
        EastMoneyZhAHisDayRequest request = new EastMoneyZhAHisDayRequest();
        request.setEnd(endDate);
        request.setBeg(startDate);
        request.setSecid(getFundSymbolCode(symbol));
        List<StockDayEntity> entities = getKEntities(period, adjust, request);
//        saveFund(entities,period);
        return entities;
    }
    /**
     * 获取1分钟线
     * @param symbol 代码
     *
     * */
    @Override
    public List<StockMinEntity> loadMinKline(String symbol) {
        EastMoneyZhAHisMinRequest request = new EastMoneyZhAHisMinRequest();
        request.setSecid(getStockSymbolCode(symbol));
        Map<String, Object> requestMap = BeanUtil.beanToMap(request);
        EastMoneyZhAHisResponse<MinLinesData> resp = eastMoneyDataApi.getMinKline(requestMap);
        //"时间","开盘","收盘","最高","最低","成交量","成交额","均价"
        LinkedList<StockMinEntity> stockList = new LinkedList<>();
        if (resp.getData() != null && !resp.getData().getTrends().isEmpty()) {
            MinLinesData data = resp.getData();
            for(int i = 0; i < data.getTrends().size(); i++){
                stockList.add(getStockMinEntity(data, i, stockList));
            }
        }
        return stockList;
    }

    @Override
    public String getStockSymbolCode(String symbol){
        if (Constants.stockMarketMap.isEmpty()){
            getStockSHMarketCode();
            getStockSZMarketCode();
            getStockBJMarketCode();
        }
        return Constants.stockMarketMap.get(symbol)+"."+symbol;
    }

    @Override
    public String getFundSymbolCode(String symbol){
        if (Constants.fundMarketMap.isEmpty()){
            getFundMarketCode();
        }
        return Constants.fundMarketMap.get(symbol)+"."+symbol;
    }

    private List<StockDayEntity> getKEntities(String period, String adjust, EastMoneyZhAHisDayRequest request) {
        request.setKlt(adjust);
        request.setFqt(period);
        Map<String, Object> requestMap = BeanUtil.beanToMap(request);
        EastMoneyZhAHisResponse<LinesData> resp = eastMoneyDataApi.getDayKline(requestMap);
        if (resp.getData() != null && !resp.getData().getKlines().isEmpty()) {
            LinesData data = resp.getData();
            //"日期","开盘","收盘","最高","最低","成交量","成交额","振幅","涨跌幅","涨跌额","换手率"
            return data.getKlines().stream().map(kline -> getDayEntity(kline, data)).collect(Collectors.toList());
        }
        return List.of();
    }
    /**
     * 获取所有市场代码产品
     * */
    @Override
    public Map<String,String> getStockSHMarketCode() {
        String ut = UUID.fastUUID().toString(true);
        //获取上海市场代码
        Map<String,Object> requestSh = Map.of("pn","1", "pz", "50000", "po", "1", "np","1",
                "ut",ut, "fltt","2", "invt","2", "fid","f3", "fs","m:1 t:2,m:1 t:23",
                "fields","f12,f13,f14,f15");
        Map<String,String> marketMap = getMarketMap(eastMoneyStockMarketDataApi.getClist(requestSh),MarketEnum.SH.getCode());
        Constants.stockMarketMap.putAll(marketMap);
        return marketMap;
    }
    @Override
    public Map<String,String> getStockSZMarketCode() {
        String ut = UUID.fastUUID().toString(true);
        //获取深圳市场代码
        Map<String,Object> requestSz = Map.of("pn","1", "pz", "50000", "po", "1", "np","1",
                "ut",ut, "fltt","2", "invt","2", "fid","f3", "fs","m:0 t:6,m:0 t:80",
                "fields","f12");
        Map<String,String> marketMap = getMarketMap(eastMoneyStockMarketDataApi.getClist(requestSz),MarketEnum.SZ.getCode());
        Constants.stockMarketMap.putAll(marketMap);
        return marketMap;
    }
    @Override
    public Map<String,String> getStockBJMarketCode() {
        //获取北京市场代码
        String ut = UUID.fastUUID().toString(true);
        Map<String,Object> requestBj = Map.of("pn","1", "pz", "50000", "po", "1", "np","1",
                "ut",ut, "fltt","2", "invt","2", "fid","f3", "fs","m:0 t:81 s:2048",
                "fields","f12");
        Map<String,String> marketMap = getMarketMap(eastMoneyStockMarketDataApi.getClist(requestBj),MarketEnum.BJ.getCode());
        Constants.stockMarketMap.putAll(marketMap);
        return marketMap;
    }


    public void getFundMarketCode() {
        String ut = UUID.fastUUID().toString(true);
        //获取ETF列表
        Map<String, Object> requestFund = Map.of("pn", "1", "pz", "5000", "po", "1", "np", "1",
                "ut", ut, "fltt", "2", "invt", "2", "wbp2u", "|0|0|0|web", "fid", "f12,f13",
                "fs", "b:MK0021,b:MK0022,b:MK0023,b:MK0024");
        Constants.fundMarketMap.putAll(getMarketMap(eastMoneyETFMarketDataApi.getClist(requestFund),null));
    }


    private Map<String,String> getMarketMap(JSONObject result,String marketId) {
        Map<String, String> marketMap = new HashMap<>();
        if (result.get("data") != null && !result.getJSONObject("data").getJSONArray("diff").isEmpty()) {
            result.getJSONObject("data").getJSONArray("diff").forEach(item -> {
                JSONObject jsonObject = JSONUtil.parseObj(item);
                marketMap.put(jsonObject.getStr("f12"), marketId==null?jsonObject.getStr("f13"):marketId);
            });
        }
        return marketMap;
    }
    /**
     * 解析周期K线
     * @param data 外层主数据
     * @param kline k线数据‘,’隔开格式
     * */
    private StockDayEntity getDayEntity(String kline, LinesData data) {
        String[] klineArr = kline.split(",");
        StockDayEntity stockDayEntity = new StockDayEntity();
        stockDayEntity.setCode(data.getCode());
        stockDayEntity.setDate(klineArr[0]);
        stockDayEntity.setOpen(klineArr[1]);
        stockDayEntity.setClose(klineArr[2]);
        stockDayEntity.setHigh(klineArr[3]);
        stockDayEntity.setLow(klineArr[4]);
        stockDayEntity.setVolume(klineArr[5]);
        stockDayEntity.setAmount(klineArr[6]);
        stockDayEntity.setAmplitude(klineArr[7]);
        stockDayEntity.setChange(klineArr[8]);
        stockDayEntity.setChangeAmount(klineArr[9]);
        stockDayEntity.setTurnover(klineArr[10]);
        stockDayEntity.setStockType(data.getMarket() + "");
        stockDayEntity.setCreateTime(LocalDateTime.now());
        stockDayEntity.setUpdateTime(LocalDateTime.now());
        return stockDayEntity;
    }

    @Async
    public void saveStockDay(List<StockDayEntity> list,String period) {
        if (EastMoneyPeriodEnum.DAILY.getCode().equals(period)){
            list.forEach(stockDayEntity -> {
                if (stockDayRepository.findByCodeAndDate(stockDayEntity.getCode(), stockDayEntity.getDate()) == null) {
                    stockDayRepository.save(stockDayEntity);
                }
            });
        }
        if(EastMoneyPeriodEnum.MIN_5.getCode().equals(period)){
            list.forEach(stockDayEntity -> {
                if (stock5Repository.findByCodeAndDate(stockDayEntity.getCode(), stockDayEntity.getDate()) == null) {
                    Stock5Entity stock5Min = new Stock5Entity();
                    BeanUtil.copyProperties(stockDayEntity, stock5Min);
                    stock5Repository.save(stock5Min);
                }
            });
        }
        if(EastMoneyPeriodEnum.MIN_15.getCode().equals(period)){
            list.forEach(stockDayEntity -> {
                if (stock15Repository.findByCodeAndDate(stockDayEntity.getCode(), stockDayEntity.getDate()) == null) {
                    Stock15Entity stock15 = new Stock15Entity();
                    BeanUtil.copyProperties(stockDayEntity, stock15);
                    stock15Repository.save(stock15);
                }
            });
        }
        if(EastMoneyPeriodEnum.MIN_30.getCode().equals(period)){
            list.forEach(stockDayEntity -> {
                if (stock30Repository.findByCodeAndDate(stockDayEntity.getCode(), stockDayEntity.getDate()) == null) {
                    Stock30Entity stock30 = new Stock30Entity();
                    BeanUtil.copyProperties(stockDayEntity, stock30);
                    stock30Repository.save(stock30);
                }
            });
        }
    }

    @Async
    public void saveFund(List<StockDayEntity> list,String period) {
        list.forEach(stockDayEntity -> {
            if (fundRepository.findByCodeAndDateAndStockPeriod(stockDayEntity.getCode(), stockDayEntity.getDate(), period) == null) {
                FundEntity fundEntity = new FundEntity();
                BeanUtil.copyProperties(stockDayEntity, fundEntity);
                fundEntity.setStockPeriod(period);
                fundRepository.save(fundEntity);
            }
        });
    }
    /**
     * 解析1分钟线且不复权
     * */
    private StockMinEntity getStockMinEntity(MinLinesData data, int index, LinkedList<StockMinEntity> stockList) {
        String[] klineArr = data.getTrends().get(index).split(",");
        StockMinEntity stockEntity = new StockMinEntity();
        if(index == 0){
            stockEntity.setOpen(data.getPreClose());
        }else{
            stockEntity.setOpen(stockList.getLast().getClose());
        }
        stockEntity.setCode(data.getCode());
        stockEntity.setTime(klineArr[0]);
        stockEntity.setClose(klineArr[2]);
        stockEntity.setHigh(klineArr[3]);
        stockEntity.setLow(klineArr[4]);
        stockEntity.setVolume(klineArr[5]);
        stockEntity.setAmount(klineArr[6]);
        stockEntity.setAvg(klineArr[7]);
        return stockEntity;
    }
}

